Command queueing is increasingly relied upon to provide improved resource utilization in conventional mass storage subsystems. In a mass storage subsystem using command queueing, I/O commands are accumulated in a buffer in the device controller which performs various known optimizations on the queued commands in order to improve the data throughput when the commands are executed by the device. For example, the commands in the queue may be reordered so that commands are executed in a sequence determined by the physical location of the data requested rather than the order in which the commands were received by the device controller. Since device access times for all but the largest data requests are determined by the time it takes to move to the block of data on the device rather than by the time it takes to actually copy the data once it has been located, ordering commands to minimize device movement can significantly reduce average access times.
Command queueing may be implemented for single disk subsystems, but it is particularly advantageous for arrays of disk which use complex distributed addressing schemes. In RAID systems, in which redundant arrays of independent/inexpensive disks are configured to appear as a single virtual disk to the user, and which are typically used in heavy I/O load environments, command queueing provides significant improvements in system performance.
Despite its inherent advantages, there are problems associated with conventional command queueing systems. Each portion of the storage subsystem operates at its own rate, but is dependent on inputs and outputs from the other parts. If either the searching capacity of a device or the carrying capacity of a bus is exceeded, some portion of the storage subsystem will be forced to remain idle until the bottleneck in the other part clears. This situation, known as saturation, is a major cause of poor I/O subsystem performance. Moreover, different portions of the subsystem respond differently to commands which request different amounts of data. When the requested data size is small, the device latency, the time it takes the device to move to the designated address, is usually the most significant factor in subsystem response time. However, when the data size is very large, the time to copy and transmit the data will far exceed the device latency, and the bandwidth of the bus rather than the device access time will become the limiting factor on subsystem performance. In a multi-spindle system, where many devices share a bus, competition among devices for bus access can cause saturation. Command queueing significantly increases the likelihood of saturating the bus when handling large I/O requests, particularly in systems where many devices share a bus.
In most conventional command queueing systems, the maximum permitted depth of the device command queue is a static system parameter. Some prior art command queueing systems have been designed so that command queue depths are effectively unlimited. In these systems, the depth of the command queue is established by a physical limit such as the size of the buffer, and this is set at a level so much greater than any queue depth which is expected to occur under actual operating circumstances that system is never expected to reach it. For example, the SCSI-2 tagged command queuing scheme described in American National Standard for Information Systems--Small Computer System Interface draft specification X3.131-19xx permits up to 256 outstanding I/O commands in the queue.
Other prior art command queueing systems have placed a relatively low limit on the potential depth of the device command queue and implemented flow control procedures to insure against overflow of commands in excess of what the queue could handle at one time. For example, some implementations of Digital Equipment Corporation's Mass Storage Control Protocol (MSCP) set a static default queue limit of 8 credits. A credit is a measure determined by the number of internal operations which a given command requires. In one implementation, however, the static limit was the sum of all the allowed credits for all the queues in a multidisk system, and these credits could be reallocated dynamically among the disks within that limit. A queue would be automatically granted more credits, within the overall limit, if the host was unable to send a command to that queue because its credit limit had been exceeded.
All known conventional command queueing systems entirely ignore the effect of I/O request size on subsystem performance. In other words, no currently available command queueing system adequately addresses the impact of saturation on optimal resource allocation for both large and small I/O request sizes.
However, most storage subsystems must handle a wide range of I/O sizes, ranging from a few bytes to hundreds of blocks. It is difficult to establish a static queue depth which will be efficient across the full range of possible I/O requests. If a relatively low queue depth is chosen, the subsystem's ability to use queue optimization techniques to minimize device access times will be severely limited. If a relatively high or unlimited queue depth is chosen, the system will be able to achieve significant reductions in device latencies when handling multiple small I/O requests, but may exceed its bus load capacity when handling large I/O requests. The potential bus load problem is even worse if the queue depth is adjustable solely in response to host demand, since this may favor additional loading of queues which have already been saturated by a few large data requests.
Accordingly, an improved system and method for managing command queueing to minimize device latencies when handling small I/O requests while avoiding bus saturation when handling large I/O requests is desirable.